package com.wcq.dessert.core;

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.SuspendableRunnable;
import com.wcq.dessert.support.*;

import java.io.Closeable;

public class PortFiber implements SuspendableRunnable, Closeable {
    /**
     * 没使用channel，channel更适合多个元素，多个线程的协程间交互
     * 由于需求是一个service由用一个线程处理，并且最多只存在一个元素，所以使用下面的in和out来代表输入输出就够了，算是个小优化
     */
//    final Channel<Object> channel = Channels.newChannel(0);
    Fiber fiber;
    public int fiberId;
    FiberPool pool;

    /** ------------临时数据，回收前清理-------------  */
    CallContext in;
    Object out;
    boolean canClose = true;

    public PortFiber(int fiberId, FiberPool pool){
        this.fiberId = fiberId;
        this.pool = pool;
        // 使用port的调度器启动，保证与PulseFiber在同一个线程
        this.fiber = new Fiber(pool.port.fiberScheduler, this).start();
    }

    @Override
    public void run() throws SuspendExecution, InterruptedException {
        Log.console("协程启动");
        while (true){
            pool.port.pulseFiber.unpark();
            // 协程阻塞
            Fiber.park();

            Call call = in.call;
            Service service = in.service;

            Object f = service.getMethodFunction(call.methodKey);
            Object[] m = call.methodParam;
            if (call.needResult){
                Object result = null;
                switch (call.methodParam.length) {
//                case 0: ((JowFunction0) f).apply(); break;
                    case 1: result = ((ReturnFunction1) f).apply(m[0]); break;
                    case 2: result = ((ReturnFunction2) f).apply(m[0], m[1]); break;
//                    case 3: ((Function3) f).apply(m[0], m[1], m[2]); break;
//                case 4: ((JowFunction4) f).apply(m[0], m[1], m[2], m[3]); break;
//                case 5: ((JowFunction5) f).apply(m[0], m[1], m[2], m[3], m[4]); break;
//                case 6: ((JowFunction6) f).apply(m[0], m[1], m[2], m[3], m[4], m[5]); break;
//                case 7: ((JowFunction7) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6]); break;
//                case 8: ((JowFunction8) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7]); break;
//                case 9: ((JowFunction9) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); break;
//                case 10: ((JowFunction10) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]); break;
                    default: break;
                }
                Call callReturn = call.createReturn();
                callReturn.result = result;

                service.port.getNode().dispatch(callReturn);
            }else{
                try {
                    switch (call.methodParam.length) {
//                case 0: ((JowFunction0) f).apply(); break;
                        case 1: ((Function1) f).apply(m[0]); break;
                        case 2: ((Function2) f).apply(m[0], m[1]); break;
//                    case 3: ((Function3) f).apply(m[0], m[1], m[2]); break;
//                case 4: ((JowFunction4) f).apply(m[0], m[1], m[2], m[3]); break;
//                case 5: ((JowFunction5) f).apply(m[0], m[1], m[2], m[3], m[4]); break;
//                case 6: ((JowFunction6) f).apply(m[0], m[1], m[2], m[3], m[4], m[5]); break;
//                case 7: ((JowFunction7) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6]); break;
//                case 8: ((JowFunction8) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7]); break;
//                case 9: ((JowFunction9) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); break;
//                case 10: ((JowFunction10) f).apply(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]); break;
                        default: break;
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }

            }

            // 当前环境执行完，清除状态
//            Log.console("channel complete 第{}个call", context.call.sn);
            service.port.contexts.remove(in.id);
        }

    }

    /**
     * run in : PulseFiber
     * @param context
     * @throws SuspendExecution
     * @throws InterruptedException
     */
    public void send(CallContext context) throws SuspendExecution, InterruptedException {
//        Log.console("channel send 第 [{}] 个call 1", context.call.sn);
        in = context;
        // 执行权让给portFiber
//        Fiber.parkAndUnpark(pool.port.pulseFiber.fiber, fiber);
        fiber.unpark();
//        Fiber.park();
        Fiber.yield();
//        Fiber.yield();
//        Log.console("channel send 第 [{}] 个call 2", context.call.sn);

    }


    /**
     * run in : PortFiber
     * @return
     * @throws SuspendExecution
     * @throws InterruptedException
     */
    public Object getWait() throws SuspendExecution, InterruptedException {
        // 执行权让给pulseFiber
        canClose = false;
//        Fiber.parkAndUnpark(fiber, pool.port.pulseFiber.fiber);

        pool.port.pulseFiber.unpark();
//        Fiber.yield();
        Fiber.park();
        return out;
    }


    /**
     * run in : PulseFiber
     * @param result
     * @throws SuspendExecution
     * @throws InterruptedException
     */
    public void result(Object result) throws SuspendExecution, InterruptedException {
//        Log.console("channel result 1");
        this.out = result;
        canClose = true;
        // 执行权让给portFiber
        fiber.unpark();
        Fiber.yield();
//        Fiber.park();
//        Log.console("channel result 2");
    }

    @Override
    public void close() {
        in = null;
        out = null;
        canClose = true;
        pool.recycle(this);
    }

    public void destroy() {
        in = null;
        out = null;
    }

    /**
     * 如果存在service调用另一个service并且需要返回结果，则协程阻塞
     * 此时PortFiber不能回收，因为它还在阻塞等待返回，如果回收
     */
    public void tryClose(){
        if (canClose)
            close();
    }

}
